<?php
namespace app\common\service;

class Http
{
	//POST数据过滤处理
	private static function build($data, $needBuild = true)
	{
		if (!is_array($data)) {
			return $data;
		}
		foreach ($data as $key => $value) {
			if (is_string($value) && class_exists('CURLFile', false) && stripos($value, '@') === 0) {
				if (($filename = realpath(trim($value, '@'))) && file_exists($filename)) {
					list($needBuild, $data[$key]) = [false, new \CURLFile($filename)];
				}
			}
		}
		return $needBuild ? http_build_query($data) : $data;
	}

	//get模拟网络请求
	public static function get($url, $query = [], $options = [])
	{
		$options['query'] = $query;
		return self::request('get', $url, $options);
	}

	//以post模拟网络请求
	public static function post($url, $data = [], $options = [])
	{
		$options['data'] = $data;
		return self::request('post', $url, $options);
	}

	//以put模拟网络请求
	public static function put($url, $data = [], $options = [])
	{
		$options['data'] = $data;
		return self::request('put', $url, $options);
	}

	//CURL模拟网络请求
	public static function request($method, $url, $options = [])
	{
		$curl = curl_init();
		if (!empty($options['query'])) {
			$url .= stripos($url, '?') !== false ? '&' : '?' . self::build($options['query']);
		}
		if (strtolower($method) === 'post') {
			curl_setopt($curl, CURLOPT_POST, true);
			curl_setopt($curl, CURLOPT_POSTFIELDS, self::build($options['data']));
		}else if (strtolower($method) === 'put') {
			curl_setopt($curl, CURLOPT_CUSTOMREQUEST,'PUT');
			curl_setopt($curl, CURLOPT_POSTFIELDS, self::build($options['data']));
		}else if (strtolower($method) === 'delete') {
			curl_setopt($curl, CURLOPT_CUSTOMREQUEST,'DELETE');
			curl_setopt($curl, CURLOPT_POSTFIELDS, self::build($options['data']));
		}
		$options['timeout'] = isset($options['timeout']) ? $options['timeout'] : 10;
		curl_setopt($curl, CURLOPT_TIMEOUT, $options['timeout']);
		if (!empty($options['header'])) {
			curl_setopt($curl, CURLOPT_HTTPHEADER, $options['header']);
		}
		if (!empty($options['referer'])) {
			curl_setopt($curl, CURLOPT_REFERER, $options['referer']);
		}
		if (!empty($options['ssl_cer']) && file_exists($options['ssl_cer'])) {
			curl_setopt($curl, CURLOPT_SSLCERTTYPE, 'PEM');
			curl_setopt($curl, CURLOPT_SSLCERT, $options['ssl_cer']);
		}
		if (!empty($options['ssl_key']) && file_exists($options['ssl_key'])) {
			curl_setopt($curl, CURLOPT_SSLKEYTYPE, 'PEM');
			curl_setopt($curl, CURLOPT_SSLKEY, $options['ssl_key']);
		}
		if (!empty($options['cookie'])) {
			curl_setopt($curl, CURLOPT_COOKIE, $options['cookie']);
		}
		if (!empty($options['agent'])) {
			curl_setopt($curl, CURLOPT_USERAGENT, $options['agent']);
		}
		curl_setopt($curl, CURLOPT_URL, $url);
		curl_setopt($curl, CURLOPT_HEADER, false);
		curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
		curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
		curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
		curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
		list($content, $status) = [curl_exec($curl), curl_getinfo($curl), curl_close($curl)];
		return $content;
	}

	public static function http_multi($urls,$options = []){//多线程
		$options['timeout'] = isset($options['timeout']) ? $options['timeout'] : 30;
		$conn = [];
		$res = [];
		$mh = curl_multi_init();
		//创建多个curl语柄
		foreach ($urls as $k => $v) {
			$conn[$k] = curl_init();
			curl_setopt($conn[$k], CURLOPT_URL, $v);
			curl_setopt($conn[$k], CURLOPT_TIMEOUT, $options['timeout']);
			curl_setopt($conn[$k], CURLOPT_MAXREDIRS, 7);
			//这里不要header，加块效率
			curl_setopt($conn[$k], CURLOPT_HEADER, 0);
			// 302 redirect
			curl_setopt($conn[$k], CURLOPT_FOLLOWLOCATION, 1);
			curl_setopt($conn[$k], CURLOPT_RETURNTRANSFER, 1);

			if (!empty($options['header'])) {
				curl_setopt($conn[$k], CURLOPT_HTTPHEADER, $options['header']);
			}
			if (!empty($options['referer'])) {
				curl_setopt($conn[$k], CURLOPT_REFERER, $options['referer']);
			}
			if (!empty($options['ssl_cer']) && file_exists($options['ssl_cer'])) {
				curl_setopt($conn[$k], CURLOPT_SSLCERTTYPE, 'PEM');
				curl_setopt($conn[$k], CURLOPT_SSLCERT, $options['ssl_cer']);
			}
			if (!empty($options['ssl_key']) && file_exists($options['ssl_key'])) {
				curl_setopt($conn[$k], CURLOPT_SSLKEYTYPE, 'PEM');
				curl_setopt($conn[$k], CURLOPT_SSLKEY, $options['ssl_key']);
			}
			if (!empty($options['cookie'])) {
				curl_setopt($conn[$k], CURLOPT_COOKIE, $options['cookie']);
			}
			if (!empty($options['agent'])) {
				curl_setopt($conn[$k], CURLOPT_USERAGENT, $options['agent']);
			}
			curl_multi_add_handle($mh, $conn[$k]);
		}
		//防止死循环耗死cpu 这段是根据网上的写法
		do {
			$mrc = curl_multi_exec($mh, $active);
			//当无数据，active=true
		} while ($mrc == CURLM_CALL_MULTI_PERFORM);
		//当正在接受数据时
		while ($active and $mrc == CURLM_OK) {
			//当无数据时或请求暂停时，active=true
			if (curl_multi_select($mh) != -1) {
				do {
					$mrc = curl_multi_exec($mh, $active);
				} while ($mrc == CURLM_CALL_MULTI_PERFORM);
			}
		}
		foreach ($urls as $k => $v) {
			curl_error($conn[$k]);
			$res[$k] = curl_multi_getcontent($conn[$k]);
			//获得返回信息
			$header[$k] = curl_getinfo($conn[$k]);
			//返回头信息
			curl_multi_remove_handle($mh, $conn[$k]);
			//释放资源
			curl_close($conn[$k]);
			//关闭语柄
		}
		curl_multi_close($mh);
		return $res;
	}

	public static function http_asyn($method,$url,$param=[]){
		$method = strtoupper($method);
		$postData = http_build_query($param);
		$host = 'tm.xuht.com';
		$fp = fsockopen('ssl://'.$host,443,$errno,$errstr,30);
		if(!$fp){
			return '请求失败';
		}else{
			//stream_set_blocking($fp,0);//开启了手册上说的非阻塞模式
			$header = "$method $url HTTP/1.1\r\n";
			$header .= "Host: $host\r\n";
			if($method == 'POST'){
				$header .= "Content-length:".strlen($postData)."\r\n";
			}
			$header .= "Connection: Close\r\n\r\n";
			if($method == 'POST'){
				$header .= $postData;
			}
			fwrite($fp, $header);
			$res = fgets($fp, 32);
			fclose($fp);
			return $res;
		}
	}

	public static function proxy_multi($urls,$postData){//代理多线程
		$res = array();
		$agents = [
			'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36',
			'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1',
			'Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11',
			'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6',
			'Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6',
			'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1',
			'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5',
			'Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5',
			'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3',
			'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3',
			'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3',
			'Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3',
			'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3',
			'Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3',
			'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3',
			'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3',
			'Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3',
			'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24',
			'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24',
			'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36'
		];
		$time = time();
		$orderno = 'DT20191120122956Qs5tud8g';
		$secret = '22768276a535ab528dc7caacc219817e';
		$txt = 'orderno='.$orderno.',secret='.$secret.',timestamp='.$time;
		$sign = strtoupper(md5($txt));
		$auth = 'sign='.$sign.'&orderno='.$orderno.'&timestamp='.$time;
		//创建多个curl语柄
		$mh = curl_multi_init();
		foreach ($urls as $k => $v) {
			$conn[$k] = curl_init();
			// 设置浏览器的特定header
			curl_setopt($conn[$k], CURLOPT_HTTPHEADER, array(
				'Proxy-Authorization:'.$auth
			));
			curl_setopt($conn[$k], CURLOPT_USERAGENT, $agents[mt_rand(0,19)]);
			//curl_setopt($conn[$k], CURLOPT_CUSTOMREQUEST, true);
			//curl_setopt($conn[$k], CURLOPT_POSTFIELDS, json_encode($postData));
			curl_setopt($conn[$k], CURLOPT_ENCODING, 'gzip, deflate, br');
			curl_setopt($conn[$k], CURLOPT_FOLLOWLOCATION, true);
			curl_setopt($conn[$k], CURLOPT_URL, $v);
			curl_setopt($conn[$k], CURLOPT_SSL_VERIFYPEER, FALSE);
			curl_setopt($conn[$k], CURLOPT_PROXY, 'http://dynamic.xiongmaodaili.com:8088'); 
			curl_setopt($conn[$k], CURLOPT_TIMEOUT,30);
			curl_setopt($conn[$k], CURLOPT_CONNECTTIMEOUT,30);
			curl_setopt($conn[$k], CURLOPT_RETURNTRANSFER, 1);
			curl_multi_add_handle($mh, $conn[$k]);
		}
		//防止死循环耗死cpu 这段是根据网上的写法
		do {
			$mrc = curl_multi_exec($mh, $active);
			//当无数据，active=true
		} while ($mrc == CURLM_CALL_MULTI_PERFORM);
		//当正在接受数据时
		while ($active and $mrc == CURLM_OK) {
			//当无数据时或请求暂停时，active=true
			if (curl_multi_select($mh) != -1) {
				do {
					$mrc = curl_multi_exec($mh, $active);
				} while ($mrc == CURLM_CALL_MULTI_PERFORM);
			}
		}
		foreach ($urls as $k => $v) {
			$error = curl_error($conn[$k]);
			if($error){
				@file_put_contents(env('runtime_path').'log/curl.log', $error.PHP_EOL, FILE_APPEND);
			}
			$res[$k] = curl_multi_getcontent($conn[$k]);
			//获得返回信息
			$header[$k] = curl_getinfo($conn[$k]);
			//返回头信息
			curl_multi_remove_handle($mh, $conn[$k]);
			//释放资源
			curl_close($conn[$k]);
			//关闭语柄
		}
		curl_multi_close($mh);
		//@file_put_contents(env('runtime_path').'log/proxy.log',json_encode($res,320));
		return $res;
	}
}